#ifndef __net_h
#define __net_h 1

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
// #include <netinet/tcp.h>
#include <linux/tcp.h>
#include <netinet/ip_icmp.h>
#include <net/if.h>
#include <net/route.h>
#include <netdb.h>
#include <linux/if_packet.h>

#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
# define BB_BIG_ENDIAN 1
# define BB_LITTLE_ENDIAN 0
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN
# define BB_BIG_ENDIAN 1
# define BB_LITTLE_ENDIAN 0
#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
# define BB_BIG_ENDIAN 1
# define BB_LITTLE_ENDIAN 0
#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#elif defined(__386__)
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#else
# error "Can't determine endianness"
#endif


#define PROC_NET_ROUTE "/proc/net/route"

#define ICMP_ID (uint16_t) get_random()

#define TV2MS(x) ((double)(x)->tv_sec * 1000.0 + (double)(x)->tv_usec / 1000.0)
#define TV2US(x) ((x)->tv_sec * 1000*1000 + (x)->tv_usec)
#define Kbps(x) ((double)(x)/1000.0)

#define socket_stream_new()     socket_new(AF_INET, SOCK_STREAM, 0)
#define socket_dgram_new()     socket_new(AF_INET, SOCK_DGRAM, 0)
#define socket_packet_new()     socket_new(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
extern int socket_new(int family, int type, int flag);
extern void sockaddr_set(struct sockaddr_in *addr, int family, uint16_t port, char *hostname);

extern struct addrinfo* wd_gethostbyname(char* domain, uint32_t* ipaddrs, int len);
extern uint32_t wd_ipaddr(char *ip_or_domain);
extern int rt_add(uint32_t dst, uint32_t gateway, uint32_t mask, char* dev);
extern int rt_del(uint32_t dst, uint32_t gateway, uint32_t mask, char* dev);
extern struct ifconf* get_ifaces();
void free_ifaces(struct ifconf* all);
extern void sock_sndtmo(int fd, int sec, int usec);
extern void sock_rcvtmo(int fd, int sec, int usec);
extern unsigned long long monotonic_us(void);
extern double cal_jitter(double* platencies, int count);
extern uint32_t get_random();
extern uint16_t port_random(uint16_t s);
extern void setnonblocking(int sock);
extern struct icmp* fill_icmp_packet(struct icmp* icmp_packet, int icmp_type, uint16_t icmp_sequ);
struct udphdr *fill_udp_packet(struct udphdr *udp_hdr, uint16_t src_port, uint16_t dest_port, uint16_t blocksize);
uint16_t icmp_check_sum(uint16_t* addr, int nleft);
void icmp_set_seq(struct icmp* icp, int seq);
void set_ttl(int fd, int ttl);
void bps2str(float bps, char* str);
void byte2str(uint32_t byte, char* str);
int getifaddr(char* ifname, void* addr, char* type);
#endif